package com.siashan.sensitive;

import com.alibaba.fastjson2.JSON;
import com.siashan.sensitive.dfa.MatchWord;
import com.siashan.sensitive.dfa.SensitiveUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * <p>
 * 敏感词检测
 *
 * <p>
 *
 * @author siashan
 * @date 2023/5/23
 * @since 1.2.1
 */
@Aspect
@Component
public class SensitiveCheckAspect {


    @Pointcut("@annotation(com.siashan.sensitive.SensitiveCheck)")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = ((MethodSignature) joinPoint.getSignature());
        Method method = signature.getMethod();


        Object[] params = joinPoint.getArgs();
        if (params.length == 0) {
            // 无参方法直接放行
            return joinPoint.proceed();
        }

        Annotation[][] annotations = method.getParameterAnnotations();
        if (annotations == null) {
            // 参数无注解直接放行
            return joinPoint.proceed();
        }

        for (int i = 0; i < annotations.length; i++) {
            Object param = params[i];
            Annotation[] paramAnn = annotations[i];
            //参数为空，直接下一个参数
            if (param == null) {
                continue;
            }
            SensitiveCheck annotation = hasAnno(paramAnn);
            if (null == annotation) {
                continue;
            }

            String str = "";

            // 判断参数类型
            if (param instanceof String) {
                str = (String) param;
            } else {
                str = JSON.toJSONString(param);
            }

            SensitiveCheckStrategy type = annotation.type();
            if (SensitiveCheckStrategy.THROW_ERROR.equals(type)) {
                MatchWord foundWord = SensitiveUtil.getFoundFirstSensitive(str);
                if (null != foundWord) {
                    String msg = annotation.throwErrorMsg();
                    String wordStr = "";
                    if (annotation.throwErrorShowWord()) {
                        wordStr = "\"" + foundWord.getMatchWord() + "\"";
                    }
                    msg = msg.replace("$sensitiveWord$", wordStr);
                    throw new SensitiveException(msg);
                }
            } else if (SensitiveCheckStrategy.REPLACE_WORD.equals(type)) {
                param = SensitiveUtil.sensitiveFilter(param, true, null);
                params[i] = param;
            }
        }
        return joinPoint.proceed(params);
    }


    private SensitiveCheck hasAnno(Annotation[] paramAnn) {
        if (paramAnn.length == 0) {
            return null;
        } else {
            for (Annotation annotation : paramAnn) {
                if (annotation.annotationType().equals(SensitiveCheck.class)) {
                    return (SensitiveCheck) annotation;
                }
            }
        }
        return null;
    }

}
